package com.lyb;

import com.lyb.constant.SystemConstant;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.regex.Pattern;

/**
 * 工具类
 *
 * @author Mr.Alpaca Dayun Zheng
 * @version 1.4.0
 */
public class Utils {
    /**
     * 判断字符串是否为数字的正则表达式
     */
    private final static Pattern NUMBER_PATTERN = Pattern.compile("-?\\d+(\\.\\d+)?");
    /**
     * 序列号，同一毫秒内用此参数来控制并发
     */
    private static long sequence = 0L;
    /**
     * 上一次生成编号的时间串，格式：yyMMddHHmmssSSS
     */
    private static String lastTime = "";
    /**
     * 命令输入标志位
     */
    private static boolean canInputFlag = true;
    /**
     * 文件输入标志位
     */
    private static boolean canFileFlag = false;
    /**
     * 系统有输出标志位
     */
    private static boolean isOutputFlag = false;
    /**
     * 输入语句
     */
    private static String userInput;
    /**
     * 文件内容
     */
    private static String fileContent;
    /**
     * 系统输出内容
     */
    private static final StringBuilder commandOutput = new StringBuilder();


    /**
     * 判断输入的路径是否为文件路径格式
     *
     * @param path 路径
     * @return 判断结果
     */
    public static boolean isFileFormat(String path) {
        return true;
//        String str = path;
//        /* 文件路径正则表达式 */
//        String regex = "([\\s\\w+:]*?/?(/.+/)?)((\\w+)\\.(\\w+))$";
//        /* 如果路径是 '\' 则替换成 '/' */
//        str = str.replace('\\', '/');
//        /* 若文件路径格式正确则格式正确 */
//        return Pattern.matches(regex, str);
    }

    /**
     * 判断输入的路径是否为目录路径格式
     *
     * @param path 路径
     * @return 判断结果
     */
    public static boolean isDirectoryFormat(String path) {
        return true;
//        /* 目录路径正则表达式 */
//        String regex = "[a-z]|[A-Z]:(\\\\[^\\\\/&?\\n]+)\\\\?";
//        /* 若文件路径格式正确则格式正确 */
//        return Pattern.matches(regex, path);
    }

    /**
     * 判断传入字符串是否可转为数字格式
     * 返回操作结果
     *
     * @param str 传入字符串
     * @return true表示该字符串可转为数字
     */
    public static boolean isNumber(String str) {
        /* 字符串不为null且匹配正则表达式 */
        return str != null && NUMBER_PATTERN.matcher(str).matches();
    }

    /**
     * 将int类型整数转换为两字节的数组，转换公式:
     * 0位 x 128 + 1位 = 整数数值
     *
     * @param number 整数，该项目使用范围为[0, 8192]
     * @return 两字节数组
     */
    public static byte[] intToByteArray(int number) {
        byte[] numberBytes = new byte[2];
        numberBytes[0] = (byte) (number / 128);
        numberBytes[1] = (byte) (number % 128);
        return numberBytes;
    }

    /**
     * 将int类型整数转换为两字节的数组，转换公式:
     * 整数数值 = 0位 x 128 + 1位
     *
     * @param number byte数组(两字节)
     * @return 整数，该项目使用范围为[0, 8192]
     */
    public static int byteArrayToInt(byte[] number) {
        int high = number[0];
        int low = number[1];
        return high * 128 + low;
    }

    /**
     * 获取系统运行时间
     * 60s以下时间单位：秒
     * 1h以下时间单位：分
     * 1d以下时间单位：小时
     * 1m以下时间单位：天
     * 1y以下时间单位：月
     * 1y以上时间单位：年
     *
     * @return 特定格式的运行时间
     */
    public static String getRunningTime() {
        long time = System.currentTimeMillis() - SystemConstant.SYSTEM_START_TIME;
        if (time < 60 * 1000) {
            return new SimpleDateFormat("已经启动了s秒").format(time);
        } else if (time < 60 * 60 * 1000) {
            return new SimpleDateFormat("已经启动了m分钟").format(time);
        } else if (time < 24 * 3600 * 1000) {
            return new SimpleDateFormat("已经启动了H小时").format(time);
        } else if (time < (long) 31 * 24 * 3600 * 1000) {
            return new SimpleDateFormat("已经启动了d天").format(time);
        } else if (time < (long) 365 * 24 * 3600 * 1000) {
            return new SimpleDateFormat("已经启动了M月").format(time);
        } else {
            return new SimpleDateFormat("已经启动了h年").format(time);
        }
    }

    /**
     * 判断传入字符串是否符合时间格式
     *
     * @param date 时间
     * @return 判断结果
     */
    public static boolean isValidDate(String date) {
        boolean convertSuccess = true;
        SimpleDateFormat format = new SimpleDateFormat("yyy-MM-dd HH:mm:ss");
        try {
            format.setLenient(false);
            format.parse(date);
        } catch (ParseException e) {
            convertSuccess = false;
        }
        return convertSuccess;
    }

    /**
     * 获取当前系统的时间
     * 格式为：yyyy-MM-dd HH:mm:ss
     *
     * @return 格式化的时间
     */
    public static String getCurrentTime() {
        /* 获取当前时间 */
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
    }

    /**
     * 将I/O设备的使用情况写入指定文件
     * 写入内容有：
     * 1.设备使用的时间
     * 2.设备ID,名称
     *
     * @param content 写入日志的内容
     * @param path    日志文件的路径
     */
    public static void log(String content, String path) {
        try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(new File(path), true))) {
            /* 写入日志内容 */
            bufferedWriter.write(content);
            bufferedWriter.newLine();
        } catch (IOException e) {
            System.out.println("写入日志文件失败!");
        }
    }

    /**
     * 将I/O设备的使用情况写入系统日志文件
     * 写入内容有：
     * 1.设备使用的时间
     * 2.设备ID,名称
     *
     * @param content 写入日志的内容
     */
    public static void log(String content) {
        try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(new File(SystemConstant.SYSTEM_LOG_PATH), true))) {
            /* 写入日志内容 */
            bufferedWriter.write(content);
            bufferedWriter.newLine();
        } catch (IOException e) {
            Utils.outCommandResult("写入日志文件失败!");
            Utils.outCommandOver();
        }
    }

    /**
     * 获取唯一id(雪花算法)
     *
     * @return id(全局唯一)
     */
    public static long getUniqueId() {
        /* 获取当前时间串，格式：yyMMddHHmmssSSS */
        String nowTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyMMddHHmmssSSS"));
        /* 机器编号 */
        String machineId = "01";

        /* 本次和上次不是同一毫秒，直接生成编号返回 */
        if (!lastTime.equals(nowTime)) {
            /* 重置序列号,更新时间串 */
            sequence = 0L;
            lastTime = nowTime;
            return Long.parseLong(nowTime + machineId + sequence);
        }

        /* 本次和上次在同一个毫秒内，需要用序列号控制并发 */
        if (sequence < 99) { /* 序列号没有达到最大值，直接生成编号返回 */
            sequence = sequence + 1;
            return Long.parseLong(nowTime + machineId + sequence);
        }
        /* 序列号达到最大值，需要等待下一毫秒的到来 */
        while (lastTime.equals(nowTime)) {
            nowTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyMMddHHmmssSSS"));
        }
        /* 重置序列号,更新时间串 */
        sequence = 0L;
        lastTime = nowTime;
        return Long.parseLong(nowTime + machineId + sequence);
    }

    /**
     * 获取可输入标记，用于GUI界面判断系统是否允许接收用户输入
     *
     * @return true表示系统接收用户输入，false表示不接收
     */
    public static boolean isCanInputFlag() {
        return canInputFlag;
    }

    /**
     * 接收GUI界面的用户命令输入，在该命令处理完成之前不接受下一次输入
     *
     * @param input 用户输入
     */
    public static void guiInput(String input) {
        userInput = input;
        canInputFlag = false;
    }

    /**
     * 获取GUI界面的用户命令输入
     * 若成功读取到命令则将允许GUI输入下一条命令
     * 反之拒绝
     *
     * @return ""表示当前GUI无命令输入
     */
    public static String getUserInput() {
        if (canInputFlag) {
            return " ";
        } else {
            canInputFlag = true;
            return userInput;
        }
    }

    /**
     * 将传入参数存储为系统接收的文件内容
     *
     * @param content 文件内容
     */
    public static void setFileContent(String content) {
        fileContent = content;
    }

    /**
     * 获取GUI界面的用户文件内容输入
     *
     * @return 文件内容
     */
    public static String getFileContent() {
        return fileContent;
    }

    /**
     * 判断当前系统是否需要输入文件内容
     *
     * @return true表示当前系统存在一新文件需要输入内容
     */
    public static boolean isCanFileFlag() {
        return canFileFlag;
    }

    /**
     * 设置当前系统的文件输入状态
     *
     * @param canFileFlag true表示当前系统存在一新文件需要输入内容
     */
    public static void setCanFileFlag(boolean canFileFlag) {
        Utils.canFileFlag = canFileFlag;
    }

    /**
     * 将传入参数添加进系统命令执行结果缓冲中
     *
     * @param result 命令执行结果
     */
    public static void outCommandResult(String result) {
        commandOutput.append(result).append("\n");
    }

    /**
     * 命令执行结尾
     */
    public static void outCommandOver() {
        commandOutput.append("========================================").append("\n");
        isOutputFlag = true;
    }


    /**
     * 获取系统命令执行结果缓冲
     *
     * @return 命令执行结果缓冲
     */
    public static String getCommandOutput() {
        String output = "";
        if (isOutputFlag) {
            isOutputFlag = false;
            output = commandOutput.toString();
            commandOutput.delete(0, commandOutput.length());
        }
        return output;
    }
}
